#pragma once

#include <string>
#include <unordered_map>

#include "ir.h"
#include "iroperand.h"
#include "semantics.h"
#include "visitor.h"

struct IRBuilder : public ASTVisitor {
    struct VarMap {
        int count = 0;
        std::unordered_map<Symbol*, IR::Variable*> mp;

        IR::Variable* Get(Symbol* sym);
        IR::Variable* Get(Type::Basic type, bool isPtr = false);
    };

    VarMap varMap;
    std::unordered_map<Semantics::Info*, IRFunction*> funcMap;
    std::vector<IRBlock*> irContinue;
    std::vector<IRBlock*> irBreak;
    IRFunction* currentFunc;

    AST::ASTNode* VisitAssignExpr(AST::AssignExpr* node) override;
    AST::ASTNode* VisitCallExpr(AST::CallExpr* node) override;
    AST::ASTNode* VisitArrayExpr(AST::ArrayExpr* node) override;
    AST::ASTNode* VisitOperatorExpr(AST::OperatorExpr* node) override;
    AST::ASTNode* VisitTernaryExpr(AST::TernaryExpr* node) override;
    AST::ASTNode* VisitLiteralExpr(AST::LiteralExpr* node) override;
    AST::ASTNode* VisitVoidExpr(AST::VoidExpr* node) override;
    AST::ASTNode* VisitIdentifierExpr(AST::IdentifierExpr* node) override;
    AST::ASTNode* VisitInitializerExpr(AST::InitializerExpr* node) override;
    AST::ASTNode* VisitCastExpr(AST::CastExpr* node) override;
    AST::ASTNode* VisitAddrExpr(AST::AddrExpr* node) override;
    AST::ASTNode* VisitArgList(AST::ArgList* node) override;
    AST::ASTNode* VisitBlock(AST::Block* node) override;
    AST::ASTNode* VisitVarDecl(AST::VarDecl* node) override;
    AST::ASTNode* VisitFuncDecl(AST::FuncDecl* node) override;
    AST::ASTNode* VisitIfStmt(AST::IfStmt* node) override;
    AST::ASTNode* VisitWhileStmt(AST::WhileStmt* node) override;
    AST::ASTNode* VisitContinueStmt(AST::ContinueStmt* node) override;
    AST::ASTNode* VisitBreakStmt(AST::BreakStmt* node) override;
    AST::ASTNode* VisitReturnStmt(AST::ReturnStmt* node) override;

  public:
    void Visit(AST::ASTNode*& node) override;
    void* Run(void* input) override;
};
